import pytesseract
import cv2
import matplotlib.pyplot as plt
import dlib
import matplotlib.patches as mpatches
from skimage import io, draw, transform, color
import numpy as np
import pandas as pd
import re

# pip install pip install dlib==19.6.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
# pip install pip install pandas==1.1.5 -i https://pypi.tuna.tsinghua.edu.cn/simple

# 图片路径
img_path = './pic/005.jpg'
# 5个特征点检测的数据库
dat_path = './dat/shape_predictor_5_face_landmarks.dat'

# 针对所需要识别的身份证照片，可能会存在身份证图像倾斜的情况，所以要对照片进行旋转修正。
# 主要通过dlib库识别人脸，找到人脸眼睛特征点，计算眼睛的倾斜角度，然后对照片进行旋转。
detector = dlib.get_frontal_face_detector()
image = io.imread(img_path)
dets = detector(image, 2)  # 使用detector进行人脸检测 dets为返回的结果
## 将识别的图像可视化
plt.figure()  # 当前图形
ax = plt.subplot(111)
ax.imshow(image)
plt.axis("off")
for i, face in enumerate(dets):
    # 在图片中标注人脸，并显示
    left = face.left()
    top = face.top()
    right = face.right()
    bottom = face.bottom()
    rect = mpatches.Rectangle((left, bottom), right - left, top - bottom,
                              fill=False, edgecolor='red', linewidth=1)
    ax.add_patch(rect)
# plt.show()

if not len(dets):
    print('未识别人脸')

# 找到人脸后，寻找眼睛特征点：
predictor = dlib.shape_predictor(dat_path)
detected_landmarks = predictor(image, dets[0]).parts()
landmarks = np.array([[p.x, p.y] for p in detected_landmarks])
## 将眼睛位置可视化
plt.figure()
ax = plt.subplot(111)
ax.imshow(image)
plt.axis("off")
plt.plot(landmarks[0:4, 0], landmarks[0:4, 1], 'ro')
for ii in np.arange(4):
    plt.text(landmarks[ii, 0] - 10, landmarks[ii, 1] - 15, ii)
# plt.show()


# 可以发现有四个特征点被找到，计算特征点之间逆时针旋转的倾斜角度：
## 计算眼睛的倾斜角度,逆时针角度
def twopointcor(point1, point2):
    """point1 = (x1,y1),point2 = (x2,y2)"""
    deltxy = point2 - point1
    corner = np.arctan(deltxy[1] / deltxy[0]) * 180 / np.pi
    return corner


## 计算多个角度求均值
corner10 = twopointcor(landmarks[1, :], landmarks[0, :])
corner23 = twopointcor(landmarks[3, :], landmarks[2, :])
corner20 = twopointcor(landmarks[2, :], landmarks[0, :])
corner = np.mean([corner10, corner23, corner20])


# print(corner10)
# print(corner23)
# print(corner20)
# print(corner)


## 计算图像的身份证倾斜的角度
def IDcorner(landmarks):
    """landmarks:检测的人脸5个特征点
       经过测试使用第0个和第2个特征点计算角度较合适
    """
    corner20 = twopointcor(landmarks[2, :], landmarks[0, :])
    corner = np.mean([corner20])
    return corner


corner = IDcorner(landmarks)
print(corner)


## 将照片转正
def rotateIdcard(image):
    """
    将照片转正
    :param image: 需要处理的图像
    :return: 旋转后的图像,旋转后人脸位置
    """
    ## 使用dlib.get_frontal_face_detector识别人脸
    detector = dlib.get_frontal_face_detector()
    dets = detector(image, 2)  # 使用detector进行人脸检测 dets为返回的结果
    ## 检测人脸的眼睛所在位置
    predictor = dlib.shape_predictor(dat_path)
    detected_landmarks = predictor(image, dets[0]).parts()
    landmarks = np.array([[p.x, p.y] for p in detected_landmarks])
    corner = IDcorner(landmarks)
    ## 旋转后的图像
    image_right = transform.rotate(image, corner, clip=False)
    image_right = np.uint8(image_right * 255)
    ## 旋转后人脸位置
    det = detector(image_right, 2)
    return image_right, det


## 转正身份证：
image = io.imread(img_path)
image_right, dets = rotateIdcard(image)

## 可视化修正后的结果
plt.figure()
ax = plt.subplot(111)
ax.imshow(image_right)
plt.axis("off")
# 在图片中标注人脸，并显示
left = dets[0].left()
top = dets[0].top()
right = dets[0].right()
bottom = dets[0].bottom()
rect = mpatches.Rectangle((left, bottom), (right - left), (top - bottom),
                          fill=False, edgecolor='red', linewidth=1)
ax.add_patch(rect)

## 照片的位置（不怎么精确）
width = right - left
high = top - bottom
# left2 = np.uint(left - 0.5 * width)
# bottom2 = np.uint(bottom + 0.5 * width)
left2 = np.uint(left - 0.4 * width)
bottom2 = np.uint(bottom + 0.75 * width)
rect = mpatches.Rectangle((left2, bottom2), 1.9 * width, 2.5 * high,
                          fill=False, edgecolor='blue', linewidth=1)
ax.add_patch(rect)
plt.show()

## 身份证上人的照片
top2 = np.uint(bottom2 + 2.5 * high)
right2 = np.uint(left2 + 1.9 * width)
image_face = image_right[top2:bottom2, left2:right2, :]
plt.imshow(image_face)
plt.axis("off")
plt.show()
# cv2.imshow('image_face', image_face)
# cv2.waitKey()

## 可以通过pytesseract库来查看检测效果，但是结果并不是很好
# text = pytesseract.image_to_string(image_right, lang='chi_simp')
# print(text)

# ## 对图像进行处理，转化为灰度图像=>二值图像
imagegray = cv2.cvtColor(image_right, cv2.COLOR_RGB2GRAY)
# cv2.imshow('imagegray', imagegray)
# cv2.waitKey()
retval, imagebin = cv2.threshold(imagegray, 120, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
## 将照片去除
imagebin[0:bottom2, left2:-1] = 255
# 高斯双边滤波
img_bilateralFilter = cv2.bilateralFilter(imagebin, 40, 75, 75)

# cv2.imshow('img_bilateralFilter', img_bilateralFilter)
# cv2.waitKey()
plt.imshow(img_bilateralFilter, cmap=plt.cm.gray)
plt.axis("off")
plt.show()

## 再次通过pytesseract库来查看检测效果，但是结果并不是很好
text = pytesseract.image_to_string(imagebin, lang='chi_sim')
# print(text)

textlist = text.split("\n")
textdf = pd.DataFrame({"text": textlist})
textdf["textlen"] = textdf.text.apply(len)
## 去除长度《＝1的行
textdf = textdf[textdf.textlen > 1].reset_index(drop=True)
print(textdf)

## 提取相应的信息
# print("姓名:", textdf.text[0])
# print("=====================")
# print("性别:", textdf.text[1].split(" ")[0])
# print("=====================")
# print("民族:", textdf.text[1].split(" ")[-1])
# print("=====================")
# yearnum = textdf.text[2].split(" ")[0]  ## 提取数字
# yearnum = re.findall("\d+", yearnum)[0]
# print("出生年:", yearnum)
# print("=====================")
# monthnum = textdf.text[2].split(" ")[1]  ## 提取数字
# monthnum = re.findall("\d+", monthnum)[0]
# print("出生月:", monthnum)
# print("=====================")
# daynum = textdf.text[2].split(" ")[2]  ## 提取数字
# daynum = re.findall("\d+", daynum)[0]
# print("出生日:", daynum)
# print("=====================")
# IDnum = textdf.text.values[-1]
# if (len(IDnum) > 18):  ## 去除不必要的空格
#     IDnum = IDnum.replace(" ", "")
# print("公民身份证号:", IDnum)
# print("=====================")
# ## 获取地址，因为地址可能会是多行
# desstext = textdf.text.values[3:(textdf.shape[0] - 1)]
# print("地址:", "".join(desstext))
# print("=====================")

# img = cv2.imread(img_path)  # 打开图片
# gray = cv2.cvtColor(image_right, cv2.COLOR_BGR2GRAY)  # 灰度处理
# cv2.imshow('gray', gray)
# retval, imagebin = cv2.threshold(gray, 50, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
# ## 将照片去除
# imagebin[0:bottom2, left2:-1] = 255
# img_bilateralFilter = cv2.bilateralFilter(imagebin, 40, 100, 100)  # 高斯双边滤波
# cv2.namedWindow("img_bilateralFilter", cv2.WINDOW_NORMAL)
# cv2.imshow('img_bilateralFilter', img_bilateralFilter)
# cv2.waitKey(0)
